package drep;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;

/**
 * Universidad Simón Bolívar
 * Curso de Redes I - Taller
 * Profesor: Ricardo Gonzalez
 * Trimestre Enero-Marzo 2011
 *
 * Proyecto 2 RD
 *
 * @author Grupo 9
 * @author Richard Simoes Ferreira
 * @author Ricardo Tocco
 *
 * @version 1.0
 *
 */

public class ControlDrep {

/**
 * Estructura de control para el programa drep
 */
    private int puertoDcli;
    private String servidorDmon;
    private int puertoDmon;
    private String rdir;
    private ClientConnection clienteDmon;
    private boolean listening;

    /**
     * Constructor de la clase ControlDrep
     *
     * @param drep_p    Puerto local para clientes dcli
     * @param s         Host de dmon
     * @param dmon_p    Puerto dmon
     * @param d         Directorio local drep
     */
    public ControlDrep (int drep_p, String s, int dmon_p, String d){
        this.puertoDcli = drep_p;
        this.servidorDmon = s;
        this.puertoDmon = dmon_p;
        this.rdir = d;
        this.clienteDmon = null;
        this.listening = true;
    }

    /**
     * Obtener puerto bien conocido para dcli
     * @return Puerto
     */
    public int getPuertoDcli(){
        return this.puertoDcli;
    }
     /**
     * Establecer el puerto bien conocido drep
     * @param p Puerto
     */
    public void setPuertoDcli(int p){
        this.puertoDcli = p;
    }
    /**
     * Obtener nombre o dirección IPv4 del servidor dmon
     * @return  nombre o dirección IPv4 del servidor dmon
     */
    public String getServidorDmon(){
        return this.servidorDmon;
    }
    /**
     * Establecer el nombre o dirección IPv4 del servidor dmon
     * @param s nombre o dirección IPv4 del servidor drmon
     */
    public void setServidorDmon(String s){
        this.servidorDmon = s;
    }
    /**
     * Obtener puerto bien conocido del servidor dmon correspondiente
     * @return Puerto
     */
    public int getPuertoDmon(){
        return this.puertoDmon;
    }
    /**
     * Obtener puerto bien conocido del servidor dmon correspondiente
     * @param p Puerto
     */
    public void setPuertoDmon(int p){
        this.puertoDmon = p;
    }
    /**
     * Obtener el camino o path del directorio local dreṕ
     * @return  El camino o path del directorio local drep
     */
    public String getRdir(){
        return this.rdir;
    }
    /**
     * Establecer el camino o path del directorio local dmon
     * @param d El camino o path del directorio local dmon
     */
    public void setRdir(String d){
        this.rdir = d;
    }
    /**
     * Obtener la estructura de comunicación del programa drep con dmon
     * @return  Estructura de comunicación del programa drep con dmon
     */
    public ClientConnection getClientDmon(){
        return this.clienteDmon;
    }
    /**
     * Establecer la estructura de comunicación del programa drep con dmon
     * @return  Estructura de comunicación del programa drep con dmon
     */
    public void setClientDmon(ClientConnection c){
        this.clienteDmon = c;
    }
    
    /**
     * Obtiene el estado del servidor Dmon, esto permite controlar el ciclo de
     * servicio del servidor.
     * @return  true si esta activado el servidor, false sino
     */
    public boolean getStatus(){
        return this.listening;
    }
    /**
     * Establece el estado del servidor en false
     */
    public void setStatusOff(){
        this.listening = false;
    }
    /**
     * Establece el estado del servidor en true
     */
    public void setStatusOn(){
        this.listening = true;
    }

    /**
     * Función que establece una sesión del programa drep con su correspondiente
     * repositorio dmon
     */
    public void iniciarSesion(){
        int status;
        String response = null;
        ErrorHandler errorH = new ErrorHandler(this);

        status = clienteDmon.sendLinea("newDrep");
        if (status<0){
            errorH.errorSolicitudIniciarSesion();
            return;
        }

        response = clienteDmon.Getlinea();

        if (response.equals("check")){
            System.out.println("inicio de sesion exitoso");
            return;
        } else if (!response.equals("excepcion")){
            //No se pudo iniciar Session
            errorH.protocolErrorNewDrep();
            return;
        } else {
            errorH.ErrorNewDrep();
            return;
        }

    }

    /**
     * Función que termina una sesión del programa drep con su correspondiente
     * repositorio dmon
     */
    public void cerrarSesion(){
        int status;
        String response = null;
        ErrorHandler errorH = new ErrorHandler(this);

        status = clienteDmon.sendLinea("disconnectDrep");
        if (status<0){
            errorH.errorSolicitudCerrarSesion();
            System.exit(-1);
        }

        response = clienteDmon.Getlinea();

        if (response.equals("check")){
            System.out.println("se ha cerrado la sesion exitosamente");
            return;
        } else {
            errorH.protocolErrorDisconnectDrep();
            System.exit(-1);
        }

    }

    /**
     * Función que muestra en pantalla los nombres y tamaños de cada uno de los
     * archivos locales al programa drep, es decir, de los archivos que estén
     * contenidos en el directorio rdir
     */
    public void ldir(){
        File  dir = new File(this.rdir);
        File [] files = dir.listFiles();
        ErrorHandler errorH = new ErrorHandler();

        if (files == null){
            //Directorio no existe o no es un directorio
            errorH.directorioNoExiste();
        } else {
            for (int i=0;i<files.length;i++){
                System.out.println(files[i].getName()+"\t"+files[i].length());
            }
        }
    }

    /**
     * Agregar un nuevo usuario dcli a la lista de usuarios dcli activos del
     * sistema RD
     * @param newusr    Nombre del nuevo usuario dcli
     * @return          0 si todo sale bien, -1 en caso contrario
     */
    public int incrementarActivosDcli (String newusr){
        int status;
        String response = null;
        ErrorHandler errorH = new ErrorHandler(this);

        status = clienteDmon.sendLinea("newDcli##%"+newusr);
        if (status<0){
            errorH.errorSolicitudIniciarSesionDcli();
            return -1;
        }

        response = clienteDmon.Getlinea();

        if (response.equals("check")){
            //inicio de sesion exitoso dcli
            return 0;
        } else if (!response.equals("excepcion")){
            //No se ha podido iniciar sesion dcli
            return -1;
        } else {
            return -2;
        }

    }

    /**
     * Eliminar un usuario dcli de la lista de usuarios dcli activos del
     * sistema RD
     * @param newusr    Nombre del nuevo usuario dcli
     * @return          0 si todo sale bien, -1 en caso contrario
     */
    public int decrementarActivosDcli (String usr){
        int status;
        String response = null;
        ErrorHandler errorH = new ErrorHandler(this);

        status = clienteDmon.sendLinea("disconnectDcli##%"+usr);
        if (status<0){
            errorH.errorSolicitudCerrarSesionDcli();
            return -1;
        }

        response = clienteDmon.Getlinea();
        
        if (response.equals("check")){
            //Cerrado exitosamente la sesion dcli
            return 0;
        } else if (!response.equals("excepcion")) {
            //Error intentando cerrar sesion dcli
            return -1;
        } else {
            //Dmon caido
            return -2;
        }

    }

    /**
     * Dcli solicita el número de todos los programas drep
     * que están activos en el sistema
     * @return  Response
     */
    public String nrep(){
        int status;
        String response = null;
        ErrorHandler errorH = new ErrorHandler(this);

        status = clienteDmon.sendLinea("nrep");
        if (status<0){
            errorH.errorSolicitudNrep();
            return null;
        }

        response = clienteDmon.Getlinea();

        //Chequear mensaje de error Protocolo
        if (response.equals("error")){
            //No se ha podido procesar la solicitud nrep
            return null;
        } else {
            //Enviar respuesta para un dcli
            return response;
        }
    }

    /*
     * Incrementa en dmon la cantidad de archivos subidos.
     */
    protected int incrementarSubidas() {
        int status;

        status = clienteDmon.sendLinea("subida");
        if (status<0){
            System.out.println("Error incermentando archivo subido");
            return -1;
        } else return 0;
    }

    /*
     * Incrementa en dmon la cantidad de archivos descargados.
     */
    protected int incrementarBajadas() {
        int status;

        status = clienteDmon.sendLinea("bajada");
        if (status<0){
            System.out.println("Error incrementando archivo descargado");
            return -1;
        } else return 0;
    }
    

    /**
     * Lista por pantalla el contenido del archivo especificado.
     *
     * @param archivo el nombre archivo del cual se obtendra el contenido a mostrar.
     */
    protected void cat(String archivo) {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] cmd = {"/bin/bash","-c","cat "+rdir+archivo};
            String cadena = "";
            Process pr = rt.exec(cmd);
            BufferedReader input =
                    new BufferedReader(new InputStreamReader(pr.getInputStream()));
            String line=null;
            while((line=input.readLine()) != null) {
                cadena += line + '\n';
            }
            System.out.println(cadena);
            int exitVal = pr.waitFor();
            if (exitVal != 0)
                System.out.println("Error en la ejecucion del comando cat");
        } catch(Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }

    /**
     * Envia a dcli solicitante la lista de todos los usuarios activos en
     * un tiempo determinado.
     */
    protected String tuser() {
        clienteDmon.sendLinea("tuser");
        return clienteDmon.Getlinea();
    }

}